package com.chenwc.util.fileutil.jarfile;

import com.chenwc.util.fileutil.WriteFile;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.FileChannel;
import java.nio.channels.ReadableByteChannel;
import java.util.Enumeration;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * 解压文件工具
 *
 * @author chenwc
 * @package com.chenwc.util.fileutil.JarFileUtil
 * @project wso2-sinicization
 * @date 2024/5/25
 */
public class Decompression {

    private static final Logger log = LoggerFactory.getLogger(Decompression.class);

    /**
     * 压缩文件解压
     *
     * @param jarFile 需要解压的jar文件
     * @param tarDir  解压后文件的输出目录
     * @throws IOException 异常信息
     */
    public static void uncompress(File jarFile, File tarDir) throws IOException {
        try (JarFile jfInst = new JarFile(jarFile)) {
            //打印jar文件内容信息
            printJarEntry(jarFile);
            Enumeration<JarEntry> enumEntry = jfInst.entries();
            while (enumEntry.hasMoreElements()) {
                JarEntry jarEntry = enumEntry.nextElement();
                //目标输出文件，把jar实体写出成文件
                File tarFile = new File(tarDir, jarEntry.getName());

                //根据jar实体创建目标输出文件
                if (jarEntry.isDirectory()) {
                    FileUtils.forceMkdir(tarFile);
                } else {
                    FileUtils.touch(tarFile);
                }
                try (InputStream ins = jfInst.getInputStream(jarEntry)) {
                    //把jar实体写出到目标文件
                    WriteFile.writeFileByInputStream(ins, tarFile.getAbsolutePath());
                }
            }
        }


    }

    /**
     * 流交换操作，把jar实体写出到目标文件
     *
     * @param ins     输入流
     * @param channel fileChannel
     */
    private static void transferStream(InputStream ins, FileChannel channel) {
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 10);
        ReadableByteChannel rbcInst = Channels.newChannel(ins);
        try {
            while (-1 != (rbcInst.read(byteBuffer))) {
                byteBuffer.flip();
                channel.write(byteBuffer);
                byteBuffer.clear();
            }
        } catch (IOException e) {
            log.error("Error occurred: ", e);
        } finally {
            try {
                if (null != rbcInst) {
                    rbcInst.close();
                }
                if (null != channel) {
                    channel.close();
                }
            } catch (IOException e) {
                log.error("Error occurred: ", e);
            }
        }
    }

    /**
     * 打印jar文件内容信息
     *
     * @param file jar文件
     */
    public static void printJarEntry(File file) {
        JarFile jfInst = null;
        try {
            jfInst = new JarFile(file);
            Enumeration<JarEntry> enumEntry = jfInst.entries();
            int fileCount = 0, dirCount = 0;
            while (enumEntry.hasMoreElements()) {
                JarEntry jarEntry = enumEntry.nextElement();
                if (jarEntry.isDirectory()) {
                    dirCount++;
                } else {
                    fileCount++;
                }
                log.debug(jarEntry.toString());
            }
            log.info("jar文件：{}, 文件总数: {}, 文件夹总数: {}", file.getName(), fileCount, dirCount);
        } catch (IOException e) {
            log.error("Error occurred: ", e);
        } finally {
            try {
                if (null != jfInst) {
                    jfInst.close();
                }
            } catch (IOException e) {
                log.error("Error occurred: ", e);
            }
        }

    }

}
